<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas文字输入</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
        }
        
        .controls {
            margin-bottom: 20px;
            display: flex;
            gap: 10px;
            align-items: center;
            flex-wrap: wrap;
            justify-content: center;
        }
        
        .control-group {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        canvas {
            border: 1px solid #ccc;
            cursor: text;
        }
        
        .canvas-input {
            position: absolute;
            border: none;
            outline: none;
            padding: 0;
            margin: 0;
            font-family: Arial, sans-serif;
            background: transparent;
            caret-color: #000;
            /* 视觉隐藏式样式 */
            box-shadow: none;
            width: 5px;
            opacity: 0;
            border-radius: 0;
        }
        
        .instructions {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #999;
            pointer-events: none;
        }
        
        .cursor {
            position: absolute;
            height: 1em;
            width: 2px;
            background-color: #000;
            animation: blink 1s infinite;
            pointer-events: none;
        }
        
        @keyframes blink {
            0%, 100% { opacity: 1; }
            50% { opacity: 0; }
        }
    </style>
</head>
<body>
    <h1>Canvas文字输入演示</h1>
    
    <div class="controls">
        <input type="text" id="textInput" placeholder="输入文字" />
        <button id="addTextBtn">添加文字</button>
        
        <div class="control-group">
            <label for="fontSize">字体大小:</label>
            <input type="range" id="fontSize" min="12" max="48" value="20">
            <span id="fontSizeValue">20px</span>
        </div>
        
        <div class="control-group">
            <label for="textColor">文字颜色:</label>
            <input type="color" id="textColor" value="#000000">
        </div>
        
        <button id="clearCanvasBtn">清空画布</button>
    </div>
    
    <canvas id="textCanvas" width="800" height="600"></canvas>
    
    <div id="instructions" class="instructions">点击画布任意位置输入文字</div>
    
    <script>
        // 获取元素
        const canvas = document.getElementById('textCanvas');
        const ctx = canvas.getContext('2d');
        const textInput = document.getElementById('textInput');
        const addTextBtn = document.getElementById('addTextBtn');
        const clearCanvasBtn = document.getElementById('clearCanvasBtn');
        const fontSize = document.getElementById('fontSize');
        const fontSizeValue = document.getElementById('fontSizeValue');
        const textColor = document.getElementById('textColor');
        const instructions = document.getElementById('instructions');
        
        // 文字数组和当前设置
        const texts = [];
        const currentSettings = {
            color: '#000000',
            size: 20
        };
        
        // 文字位置管理
        const textPosition = {
            x: 20,
            y: 30,
            lineHeight: 25
        };
        
        // 当前编辑状态
        let editingText = null;
        let cursorPosition = 0;
        let cursorElement = null;
        
        // 初始化画布
        function initCanvas() {
            clearCanvas();
            drawInstructions();
        }
        
        // 绘制提示文字
        function drawInstructions() {
            ctx.fillStyle = '#999';
            ctx.font = '16px Arial';
            ctx.textAlign = 'center';
            ctx.fillText('点击画布任意位置输入文字', canvas.width/2, canvas.height/2);
            ctx.textAlign = 'left';
        }
        
        // 清空画布和重置位置
        function clearCanvas() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            texts.length = 0; // 清空文字数组
            resetTextPosition(); // 重置文字位置
            instructions.style.display = 'block';
            
            // 清除编辑状态
            if (editingText) {
                editingText = null;
                cursorPosition = 0;
                removeCursor();
            }
        }
        
        // 只清空画布但保留文字数组
        function clearCanvasOnly() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            instructions.style.display = 'none';
        }
        
        // 重置文字位置
        function resetTextPosition() {
            textPosition.x = 20;
            textPosition.y = 30;
            textPosition.lineHeight = currentSettings.size + 10;
        }
        
        // 绘制文字（支持换行）
        function drawText(text, x, y, color, size) {
            ctx.fillStyle = color;
            ctx.font = `${size}px Arial`;
            
            // 设置最大宽度
            const maxWidth = canvas.width - x - 20;
            const lineHeight = size + 5;
            
            // 如果文字宽度小于最大宽度，直接绘制
            if (ctx.measureText(text).width <= maxWidth) {
                ctx.fillText(text, x, y);
                return { height: lineHeight, lines: 1 }; // 返回行高和行数
            }
            
            // 否则进行换行处理
            let words = text.split('');
            let line = '';
            let currentY = y;
            let lines = 1;
            
            for (let n = 0; n < words.length; n++) {
                let testLine = line + words[n];
                let metrics = ctx.measureText(testLine);
                let testWidth = metrics.width;
                
                if (testWidth > maxWidth && n > 0) {
                    ctx.fillText(line, x, currentY);
                    line = words[n];
                    currentY += lineHeight;
                    lines++;
                } else {
                    line = testLine;
                }
            }
            
            ctx.fillText(line, x, currentY);
            return { height: currentY - y + lineHeight, lines: lines }; // 返回总高度和行数
        }
        
        // 重新绘制所有文字
        function redrawCanvas() {
            clearCanvasOnly(); // 只清空画布，不清空texts数组
            texts.forEach(item => {
                drawText(item.text, item.x, item.y, item.color, item.size);
            });
            
            // 如果正在编辑，重新创建光标
            if (editingText) {
                createCursor();
            }
        }
        
        // 添加文字到画布（从左上角开始顺序排列）
        function addText() {
            const text = textInput.value.trim();
            if (text) {
                // 检查是否需要换行
                ctx.font = `${currentSettings.size}px Arial`;
                const textWidth = ctx.measureText(text).width;
                
                if (textPosition.x + textWidth > canvas.width - 20) {
                    textPosition.x = 20;
                    textPosition.y += textPosition.lineHeight;
                }
                
                // 如果超出画布高度，重置到顶部
                if (textPosition.y > canvas.height - 20) {
                    clearCanvas(); // 清空画布并重置位置
                }
                
                // 保存文字对象
                texts.push({
                    text: text,
                    x: textPosition.x,
                    y: textPosition.y,
                    color: currentSettings.color,
                    size: currentSettings.size
                });
                
                // 绘制文字
                const textMetrics = drawText(text, textPosition.x, textPosition.y, currentSettings.color, currentSettings.size);
                
                // 更新下一个文字的位置
                textPosition.x += textWidth + 10; // 使用实际文字宽度更新位置
                
                // 清空输入框
                textInput.value = '';
                textInput.focus();
            }
        }
        
        // 查找点击位置附近的文字
        function findTextAtPosition(x, y) {
            for (let i = 0; i < texts.length; i++) {
                const textObj = texts[i];
                ctx.font = `${textObj.size}px Arial`;
                
                // 简单的边界检测
                const textWidth = ctx.measureText(textObj.text).width;
                const textHeight = textObj.size;
                
                if (x >= textObj.x && x <= textObj.x + textWidth &&
                    y >= textObj.y - textHeight && y <= textObj.y) {
                    return {
                        index: i,
                        textObj: textObj,
                        x: textObj.x,
                        y: textObj.y
                    };
                }
            }
            return null;
        }
        
        // 计算光标在文字中的位置
        function calculateCursorPosition(text, fontSize, clickX, textX) {
            ctx.font = `${fontSize}px Arial`;
            
            // 遍历每个字符，找到最接近点击位置的字符索引
            for (let i = 0; i <= text.length; i++) {
                const width = ctx.measureText(text.substring(0, i)).width;
                if (textX + width >= clickX) {
                    return i;
                }
            }
            return text.length;
        }
        
        // 计算光标在换行文字中的实际位置
        function calculateCursorActualPosition(text, fontSize, cursorPos, startX, startY) {
            ctx.font = `${fontSize}px Arial`;
            
            // 设置最大宽度
            const maxWidth = canvas.width - startX - 20;
            const lineHeight = fontSize + 5;
            
            // 如果文字宽度小于最大宽度，直接计算位置
            if (ctx.measureText(text).width <= maxWidth) {
                const width = ctx.measureText(text.substring(0, cursorPos)).width;
                return { x: startX + width, y: startY };
            }
            
            // 否则进行换行处理
            let words = text.split('');
            let line = '';
            let currentY = startY;
            let currentX = startX;
            let currentPos = 0;
            
            for (let n = 0; n < words.length; n++) {
                let testLine = line + words[n];
                let metrics = ctx.measureText(testLine);
                let testWidth = metrics.width;
                
                if (testWidth > maxWidth && n > 0) {
                    // 检查光标是否在当前行
                    if (currentPos + line.length >= cursorPos) {
                        const remainingPos = cursorPos - currentPos;
                        const width = ctx.measureText(line.substring(0, remainingPos)).width;
                        return { x: startX + width, y: currentY };
                    }
                    
                    line = words[n];
                    currentY += lineHeight;
                    currentX = startX;
                    currentPos += line.length;
                } else {
                    line = testLine;
                }
                
                // 检查光标是否在当前行末尾
                if (n === cursorPos - 1) {
                    return { x: currentX + testWidth, y: currentY };
                }
            }
            
            // 光标在最后一行
            const remainingPos = cursorPos - currentPos;
            const width = ctx.measureText(line.substring(0, remainingPos)).width;
            return { x: startX + width, y: currentY };
        }
        
        // 创建光标元素
        function createCursor() {
            // 移除现有的光标
            removeCursor();
            
            // 创建新的光标元素
            cursorElement = document.createElement('div');
            cursorElement.className = 'cursor';
            
            // 计算光标位置（支持换行）
            const textObj = editingText.textObj;
            const cursorActualPos = calculateCursorActualPosition(
                textObj.text, 
                textObj.size, 
                cursorPosition, 
                textObj.x, 
                textObj.y
            );
            
            cursorElement.style.left = (cursorActualPos.x + canvas.offsetLeft) + 'px';
            cursorElement.style.top = (cursorActualPos.y - textObj.size + 2 + canvas.offsetTop) + 'px';
            cursorElement.style.height = textObj.size + 'px';
            
            document.body.appendChild(cursorElement);
        }
        
        // 移除光标元素
        function removeCursor() {
            if (cursorElement) {
                cursorElement.remove();
                cursorElement = null;
            }
        }
        
        // 处理画布点击事件
        function handleCanvasClick(e) {
            const rect = canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            // 查找点击位置的文字
            const foundText = findTextAtPosition(x, y);
            
            if (foundText) {
                // 开始编辑文字
                editingText = foundText;
                cursorPosition = calculateCursorPosition(foundText.textObj.text, foundText.textObj.size, x, foundText.x);
                createCursor();
                
                // 创建编辑输入框
                createEditInput(foundText.textObj.x, foundText.textObj.y);
            } else {
                // 在画布左上角添加新文字（满足用户需求）
                createCanvasInput(textPosition.x, textPosition.y);
            }
        }
        
        // 创建编辑输入框
        function createEditInput(x, y) {
            // 移除已存在的输入框
            const existingInput = document.querySelector('.canvas-input');
            if (existingInput) {
                existingInput.remove();
            }
            
            // 创建输入框元素
            const input = document.createElement('input');
            input.type = 'text';
            input.className = 'canvas-input';
            
            // 调整输入框定位，使其与Canvas文字对齐
            input.style.left = (x + canvas.offsetLeft) + 'px';
            // 使用textBaseline调整输入框垂直位置，使其与Canvas文字baseline对齐
            ctx.textBaseline = 'alphabetic';
            input.style.top = (y + canvas.offsetTop) + 'px';
            
            input.style.fontSize = editingText.textObj.size + 'px';
            input.style.color = editingText.textObj.color;
            input.style.height = editingText.textObj.size + 'px';
            input.style.lineHeight = editingText.textObj.size + 'px';
            input.value = editingText.textObj.text;
            
            // 设置光标位置
            input.setSelectionRange(cursorPosition, cursorPosition);
            
            // 添加到body
            document.body.appendChild(input);
            
            // 聚焦到输入框
            input.focus();
            
            // 处理输入确认
            input.addEventListener('blur', function() {
                saveEditedText(input);
            });
            
            input.addEventListener('keypress', function(e) {
                if (e.key === 'Enter') {
                    saveEditedText(input);
                }
            });
            
            // 处理按键事件以移动光标
            input.addEventListener('keydown', function(e) {
                // 延迟一小段时间后更新光标位置
                setTimeout(() => {
                    cursorPosition = input.selectionStart;
                    createCursor();
                }, 10);
            });
            
            // 实时更新文字显示
            input.addEventListener('input', function() {
                updateEditText(input.value);
            });
        }
        
        // 实时更新编辑中的文字
        function updateEditText(newText) {
            // 更新文字对象
            texts[editingText.index].text = newText;
            
            // 重新绘制画布
            redrawCanvas();
            
            // 重新创建光标
            createCursor();
        }
        
        // 保存编辑后的文字
        function saveEditedText(input) {
            const newText = input.value;
            
            // 更新文字对象
            texts[editingText.index].text = newText;
            
            // 重新绘制画布
            redrawCanvas();
            
            // 移除输入框和光标
            input.remove();
            removeCursor();
            
            // 重置编辑状态
            editingText = null;
            cursorPosition = 0;
        }
        
        // 在画布上创建新文字输入框（修改为视觉隐藏式并定位到左上角）
        function createCanvasInput(x, y) {
            // 移除已存在的输入框
            const existingInput = document.querySelector('.canvas-input');
            if (existingInput) {
                existingInput.remove();
            }
            
            // 创建输入框元素
            const input = document.createElement('input');
            input.type = 'text';
            input.className = 'canvas-input';
            
            // 将输入框定位到指定位置（默认为左上角）
            input.style.left = (x + canvas.offsetLeft) + 'px';
            // 使用textBaseline调整输入框垂直位置，使其与Canvas文字baseline对齐
            ctx.textBaseline = 'alphabetic';
            input.style.top = (y + canvas.offsetTop) + 'px';
            
            input.style.fontSize = currentSettings.size + 'px';
            input.style.color = currentSettings.color;
            input.style.height = currentSettings.size + 'px';
            input.style.lineHeight = currentSettings.size + 'px';
            input.placeholder = '';
            
            // 视觉隐藏式输入框样式
            input.style.backgroundColor = 'transparent';
            input.style.border = 'none';
            input.style.outline = 'none';
            input.style.boxShadow = 'none';
            
            // 添加到body
            document.body.appendChild(input);
            
            // 聚焦到输入框
            input.focus();
            
            // 处理输入确认
            input.addEventListener('blur', function() {
                saveCanvasText(input);
            });
            
            input.addEventListener('keypress', function(e) {
                if (e.key === 'Enter') {
                    saveCanvasText(input);
                }
            });
            
            // 实时更新文字显示
            input.addEventListener('input', function() {
                previewCanvasText(input.value);
            });
        }
        
        // 预览新输入的文字
        function previewCanvasText(text) {
            // 保存当前文字数组
            const originalTexts = [...texts];
            
            // 重新绘制画布并包含预览文字
            clearCanvasOnly();
            texts.forEach(item => {
                drawText(item.text, item.x, item.y, item.color, item.size);
            });
            
            // 如果有文字内容，则添加到画布预览
            if (text.trim()) {
                // 计算预览文字的位置
                let previewX = textPosition.x;
                let previewY = textPosition.y;
                
                // 如果文字数组不为空，计算最后一个文字的位置
                if (texts.length > 0) {
                    const lastText = texts[texts.length - 1];
                    ctx.font = `${lastText.size}px Arial`;
                    const lastTextWidth = ctx.measureText(lastText.text).width;
                    
                    // 计算预览文字的位置
                    previewX = lastText.x + lastTextWidth + 10;
                    previewY = lastText.y;
                    
                    // 检查是否需要换行
                    ctx.font = `${currentSettings.size}px Arial`;
                    const textWidth = ctx.measureText(text).width;
                    
                    if (previewX + textWidth > canvas.width - 20) {
                        previewX = 20;
                        previewY += textPosition.lineHeight;
                    }
                }
                
                // 绘制预览文字
                drawText(text, previewX, previewY, currentSettings.color, currentSettings.size);
            }
        }
        
        // 保存画布文字 - 修改为按顺序排列
        function saveCanvasText(input) {
            const text = input.value.trim();
            if (text) {
                // 使用顺序排列逻辑而不是直接使用点击位置
                // 检查是否需要换行
                ctx.font = `${currentSettings.size}px Arial`;
                const textWidth = ctx.measureText(text).width;
                
                if (textPosition.x + textWidth > canvas.width - 20) {
                    textPosition.x = 20;
                    textPosition.y += textPosition.lineHeight;
                }
                
                // 如果超出画布高度，重置到顶部
                if (textPosition.y > canvas.height - 20) {
                    clearCanvas(); // 清空画布并重置位置
                }
                
                // 保存文字对象
                texts.push({
                    text: text,
                    x: textPosition.x,
                    y: textPosition.y,
                    color: currentSettings.color,
                    size: currentSettings.size
                });
                
                // 绘制文字
                const textMetrics = drawText(text, textPosition.x, textPosition.y, currentSettings.color, currentSettings.size);
                
                // 更新下一个文字的位置
                textPosition.x += textWidth + 10; // 使用实际文字宽度更新位置
                
                // 重新绘制画布
                redrawCanvas();
            }
            
            // 移除输入框
            input.remove();
        }
        
        // 更新字体大小显示
        function updateFontSizeDisplay() {
            fontSizeValue.textContent = `${fontSize.value}px`;
            currentSettings.size = parseInt(fontSize.value);
            // 更新行高
            textPosition.lineHeight = currentSettings.size + 10;
        }
        
        // 更新文字颜色
        function updateTextColor() {
            currentSettings.color = textColor.value;
        }
        
        // 事件监听器
        addTextBtn.addEventListener('click', addText);
        
        textInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                addText();
            }
        });
        
        clearCanvasBtn.addEventListener('click', () => {
            clearCanvas();
            drawInstructions();
        });
        
        canvas.addEventListener('click', handleCanvasClick);
        
        fontSize.addEventListener('input', updateFontSizeDisplay);
        
        textColor.addEventListener('input', updateTextColor);
        
        // 初始化
        initCanvas();
    </script>
</body>
</html>